package com.novel.download.service.impl;

import com.novel.download.controller.resp.Catalogue;
import com.novel.download.controller.resp.CatalogueResp;
import com.novel.download.controller.resp.ReadCatalogueResp;
import com.novel.download.controller.resp.SearchResp;
import com.novel.download.service.NovelService;
import com.novel.download.utils.ReadBookUtils;
import com.novel.download.utils.ThreadUtils;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Future;

//该网站可以跳过反义词的反爬虫
@Service
public class Biquge5200NovelService implements NovelService {

    private static final String name = "笔趣阁5200";
    private static final String domain = "https://www.b520.cc/";
    private static final String search = "modules/article/search.php?searchkey=%s";
    private static final List<String> exclude = Arrays.asList("    一秒记住【39小说网 www.ishubao.org】，精彩小说无弹窗免费阅读！ ", "");

    @Override
    public String getName() {
        return name;
    }

    public Map<String, Boolean> ping() {
        Map<String, Boolean> result = new HashMap<>();
        result.put(name, false);
        Document document = ReadBookUtils.getDocument(domain);
        result.put(name, Objects.nonNull(document));
        return result;
    }

    public Map<String, List<SearchResp>> search(String bookName) {
        HashMap<String, List<SearchResp>> result = new HashMap<>();
        result.put(name, new ArrayList<>());
        Document document = ReadBookUtils.getDocument(String.format(domain + search, bookName));
        if (Objects.isNull(document)) {
            return result;
        }
        Elements trs = document.getElementsByTag("tr");
        if (trs.size() == 1) {
            return result;
        }
        for (int i = 1; i < trs.size(); i++) {
            Element element = trs.get(i);
            Elements tds = element.getElementsByTag("td");
            SearchResp searchResp = new SearchResp();
            searchResp.setNet(name);
            searchResp.setBookName(tds.get(0).getElementsByTag("a").text());
            searchResp.setBookUrl(tds.get(0).getElementsByTag("a").attr("href").substring(domain.length()));
            searchResp.setNewNode(tds.get(1).getElementsByTag("a").text());
            searchResp.setNewNodeUrl(tds.get(1).getElementsByTag("a").attr("href").substring(domain.length()));
            searchResp.setAuthor(tds.get(2).text());
            searchResp.setBookSize(tds.get(3).text());
            searchResp.setUpdateTime(tds.get(4).text());
            searchResp.setStatus(tds.get(5).text());
            result.get(name).add(searchResp);
        }
        return result;
    }

    public CatalogueResp catalogue(String url, String net) {
        CatalogueResp resp = new CatalogueResp();
        resp.setNetWorkName(name);
        resp.setCatalogueList(new ArrayList<>());
        Document document = ReadBookUtils.getDocument(domain + url);
        if (Objects.isNull(document)) {
            return resp;
        }
        resp.setBookName(document.getElementsByTag("h1").text());
        Element chapterlist = document.getElementById("list");
        Elements cas = chapterlist.getElementsByTag("a");
        for (int i = 0; i < cas.size(); i++) {
            //跳过前9个最新章节
            if (i <= 8) {
                continue;
            }
            Element ca = cas.get(i);
            Catalogue catalogue = new Catalogue();
            catalogue.setBookUrl(url);
            catalogue.setNet(name);
            catalogue.setCatalogueName(ca.text());
            catalogue.setCatalogueUrl(ca.attr("href"));
            resp.getCatalogueList().add(catalogue);
        }
        return resp;
    }

    public ReadCatalogueResp readCatalogue(String url) {
        ReadCatalogueResp resp = new ReadCatalogueResp();
        Document document = ReadBookUtils.getDocument(url);
        if (Objects.isNull(document)) {
            return resp;
        }
        StringBuilder text = new StringBuilder();
        Elements contents = document.getElementById("content").getElementsByTag("p");
        for (Element content : contents) {
            text.append(content.text()).append("\n");
        }
        resp.setText(text.toString());
        resp.setText(ReadBookUtils.split(resp.getText(), exclude));
        resp.setTitle(document.getElementsByTag("h1").text());
        resp.setBookName(document.getElementsByClass("con_top").get(0).getElementsByTag("a").get(2).text());
        Elements nextTag = document.getElementsByClass("bottem1").get(0).getElementsByTag("a");
        String catalogueUrl = nextTag.get(2).attr("href");
        String nextUrl = nextTag.get(3).attr("href");
        if (!catalogueUrl.equals(nextUrl)) {
            resp.setNextUrl(nextUrl);
        }
        return resp;
    }

    @Override
    public void download(String url, String from, String net, HttpServletResponse response) throws Exception {
        CatalogueResp catalogueResp = catalogue(url, net);
        String bookName = catalogueResp.getBookName();
        // 设置输出的格式
        response.reset();
        response.setContentType("text/plain");
        response.addHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(bookName, "UTF-8") + "\"");
        writeStream(bookName + "\n\n", response);
        List<Catalogue> catalogueList = catalogueResp.getCatalogueList();
        List<Future<String>> futureList = new ArrayList<>();
        boolean flag = !StringUtils.hasLength(from);
        for (Catalogue catalogue : catalogueList) {
            if (StringUtils.hasLength(from) && from.equals(catalogue.getCatalogueName())) {
                flag = true;
            }
            if (flag) {
                Future<String> future = ThreadUtils.submit(() -> {
                    ReadCatalogueResp readCatalogueResp = readCatalogue(catalogue.getCatalogueUrl());
                    String title = readCatalogueResp.getTitle();
                    String text = readCatalogueResp.getText();
                    return title + "\n  " + text + "\n";
                });
                futureList.add(future);
            }
        }
        for (Future<String> stringFuture : futureList) {
            String s = stringFuture.get();
            writeStream(s, response);
        }
        response.flushBuffer();
    }

    private void writeStream(String s, HttpServletResponse response) {
        byte[] b = new byte[1024];
        int len;
        ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
        try {
            while ((len = inputStream.read(b)) > 0)
                response.getOutputStream().write(b, 0, len);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
